/* $ZEL: sis1100_sc_linux.h,v 1.9 2006/05/15 17:57:58 wuestner Exp $ */

/*
 * Copyright (c) 2001-2004
 * 	Peter Wuestner.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#ifndef _sis1100_sc_linux_h_
#define _sis1100_sc_linux_h_

#define SGL_SIZE 128
#define DMA_MAX (PAGE_SIZE*(SGL_SIZE-1))

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
#define USE_SGL
#else
#error no USE_SGL
#endif
/*#undef USE_SGL*/

struct sis1100_dmabuf {
    size_t size;
    void* cpu_addr;
    dma_addr_t dma_handle;
};

struct sis1100_dmapage {
    void* cpu_addr;
    dma_addr_t dma_handle;
};

struct mmapdma {
        int valid;
};

struct handlercommand {
    volatile enum handlercomm command;
    spinlock_t lock;
};

struct sis1100_softc;

struct sis1100_fdata {
    struct list_head list;
/* OS specific*/
    struct sis1100_softc* sc;
/*common*/
    struct mmapdma mmapdma;
    size_t mindmalen_r, mindmalen_w;
    enum sis1100_hw_type old_remote_hw;
    enum sis1100_subdev subdev;
    int32_t vmespace_am;
    u_int32_t vmespace_datasize;
    int fifo_mode;
    int last_prot_err;
    u_int32_t owned_irqs;
    pid_t pid;
    int sig;
};

/*
 * each block has to start at a page boundary and its length has to be a
 * multiple of the page size
 * all blocks have to have the same size
 * at least two blocks are required
 */
struct demand_dma_block {
    char* uaddr; /* user virtual address of this block */
    size_t size;                  /* size of ONE block of mapped user pages */

    int nsegs; /* maximum number of mapped user pages */
    int nr_pages; /* number of pages returned from sgl_map_user_pages */
    struct scatterlist* sglist;
    int sgcount;
    int dsegs; /* number of pages for PLX descriptors */
    struct sis1100_dmapage* desc_pages;
    u_int32_t dmadpr0;
    int used;
};

/* demand_dma should be identical to the bsd version */
struct demand_dma {
    struct semaphore sem;         /* protects this structure */
    spinlock_t spin;              /* protects is_blocked and block[].used */

    enum dmastatus status;        /* invalid | ready | running */
    struct sis1100_fdata *owner;

    char* uaddr;                  /* user virtual address of the first block */
    size_t size;                  /* size of ONE block of mapped user pages */
    int numblocks;                /* number of blocks */
    struct demand_dma_block* block;
    int active_block;
    int last_block;
    int is_blocked;
};

struct sis1100_softc {
/* OS specific*/
    volatile u_int8_t *plxmembase; /* kernel virtual address */
    u_int32_t plxmemlen;           /* size */
    u_long plx_addr;               /* physical address */

    volatile u_int8_t*reg_base;    /* kernel virtual address */
    u_int32_t reg_size;            /* size */
    u_long reg_addr;               /* physical address */

    volatile u_int8_t*rem_base;    /* kernel virtual address */
    u_int32_t rem_size;            /* size */
    u_long rem_addr;               /* physical address */

    struct pci_dev *pcidev;
    int unit;
    int handler_pid;
    struct task_struct* handler_task;
    struct sched_param sched_param;
    struct completion handler_completion;
#ifndef USE_SGL
    struct kiobuf* iobuf;
#endif
    struct sis1100_dmabuf descbuf;
    struct scatterlist sglist[SGL_SIZE];


/* OS specific definition but common use */
    struct semaphore sem_hw;         /* protects hardware */
    struct semaphore sem_fdata_list; /* protects fdata_list_head */
    struct semaphore sem_irqinfo;    /* protects irq_vects, pending_irqs
                                        and new_irqs */
    spinlock_t lock_intcsr;          /* protects INTCSR of PLX */
    spinlock_t lock_doorbell;        /* protects sc.doorbell */
    spinlock_t lock_lemo_status;     /* protects sc.lemo_status */
    wait_queue_head_t handler_wait;
    wait_queue_head_t local_wait;
    wait_queue_head_t remoteirq_wait;
    struct timer_list link_up_timer;

/* common */
    struct sis1100_fdata* fdatalist[sis1100_MINORUTMASK+1];
    struct list_head fdata_list_head;
    u_int32_t local_ident, remote_ident;
    volatile enum sis1100_hw_type remote_hw, old_remote_hw;
    volatile u_int32_t doorbell;
    volatile u_int32_t lemo_status;
    volatile u_int32_t mbx0;
    volatile int got_irqs;
    struct irq_vects irq_vects[8];
    u_int32_t pending_irqs, new_irqs;
    struct handlercommand handlercommand;
    loff_t ram_size;
    int dsp_present;
    int remote_endian; /* 0: little 1: big*/
    int user_wants_swap;
    volatile u_int32_t last_opt_csr; /* used by handlercomm_lemo */
    struct demand_dma demand_dma;
    void (*plxirq_dma0_hook)(struct sis1100_softc*);

#if 0
    int dma_dac; /* use 64bit dual address cycle for dma */
    int no_dma;  /* even 32bit dma not available */
#endif
};

extern struct sis1100_softc *sis1100_devdata[sis1100_MAXCARDS];

extern struct file_operations sis1100_fops;

#define SIS1100FD(file) ((struct sis1100_fdata*)(file)->private_data)
#define SIS1100SC(file) (((struct sis1100_fdata*)(file)->private_data)->sc)

#define _plxreadreg(sc, offset) readl((sc)->plxmembase+(offset))
#define _plxwritereg(sc, offset, val) writel(val, (sc)->plxmembase+(offset))
#define _plxreadbreg(sc, offset) readb((sc)->plxmembase+(offset))
#define _plxwritebreg(sc, offset, val) writeb(val, (sc)->plxmembase+(offset))

#define plxreadlocal0(sc, offset) readl((sc)->reg_base+(offset))
#define plxreadlocal0b(sc, offset) readb((sc)->reg_base+(offset))
#define plxwritelocal0(sc, offset, val) writel(val, (sc)->reg_base+(offset))
#define plxwritelocal0b(sc, offset, val) writeb(val, (sc)->reg_base+(offset))
#define plxrawreadlocal0(sc, offset) __raw_readl((sc)->reg_base+(offset))
#define plxrawwritelocal0(sc, offset, val) __raw_writel(val, (sc)->reg_base+(offset))

#define rmb_plx() rmb()
#define rmb_reg() rmb()
#define wmb_plx() wmb()
#define wmb_reg() wmb()
#define mb_plx() mb()
#define mb_reg() mb()

int  sis1100_open(struct inode *inode, struct file *file);
int  sis1100_release(struct inode *inode, struct file *file);
#ifdef HAVE_UNLOCKED_IOCTL
long  sis1100_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
#else
int  sis1100_ioctl(struct inode *inode, struct file *file,
    	    	unsigned int cmd, unsigned long arg);
#endif
#ifdef HAVE_COMPAT_IOCTL
long sis1100_ioctl32(struct file * file, unsigned int cmd, unsigned long arg);
long _sis1100_ioctl(struct sis1100_softc* sc, struct sis1100_fdata* fd,
    unsigned int cmd, void* data);
#endif
loff_t sis1100_llseek(struct file* file, loff_t offset, int orig);
int  sis1100_mmap(struct file * file, struct vm_area_struct * vma);
ssize_t sis1100_read(struct file* file, char* buf, size_t count,
    	    	loff_t* ppos);
ssize_t sis1100_write(struct file* file, const char* buf, size_t count,
    	    	loff_t* ppos);
unsigned int sis1100_poll(struct file* file,
                struct poll_table_struct* poll_table);

int sis1100_irq_thread(void* data);
void sis1100_link_up_handler(unsigned long data);

irqreturn_t sis1100_intr(int irq, void *vsc, struct pt_regs *regs);
int  sis1100_init(struct sis1100_softc* sc);
void sis1100_done(struct sis1100_softc* sc);

void sis1100_ioctl32_init(void);
void sis1100_ioctl32_exit(void);

#endif
